package main

import (
	"github.com/golang-module/carbon/v2"
	"github.com/spf13/viper"
	ssl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205"
	"log"
	"os"
	"strings"
)

var logger *log.Logger

func init() {
	logger = log.New(os.Stdout, "", log.Lshortfile|log.LstdFlags)
	InitConfig()
	InitDateFormat()
	InitTencentApi()
}

func InitDateFormat() {
	carbon.SetDefault(carbon.Default{
		Layout:       carbon.DateTimeLayout,
		Timezone:     carbon.PRC,
		WeekStartsAt: carbon.Sunday,
		Locale:       "zh-CN",
	})
}

func main() {
	servers, err := ParseNginxConfig4Cert(viper.GetString("nginx.config-file"))
	if err != nil {
		logger.Panicf("nginx文件解析异常: %s", err)
	}
	logger.Printf("解析到%d条ssl配置", len(servers))
	updateAllCert(servers)
}

func updateAllCert(servers []IServer) {
	dnsRs, err := DescribeDomainList()
	if err != nil {
		logger.Panic("域名列表查询失败: ", err)
	}
	if dnsRs.Response.DomainList == nil {
		logger.Panic("账号名下域名列表为空，暂时只支持为同账号名下域名自动申请证书")
	}
	domainList := make([]string, 0, len(dnsRs.Response.DomainList))
	for _, item := range dnsRs.Response.DomainList {
		if *item.Status == "ENABLE" {
			domainList = append(domainList, *item.Punycode)
		}
	}
	logger.Printf("查询到名下域名%d条。暂时只支持为同账号名下域名自动申请证书",
		len(domainList))
	isBelong := func(domain string) bool {
		for _, item := range domainList {
			if strings.HasSuffix(domain, item) {
				return true
			}
		}
		return false
	}

	rs, err := ListCertificates()
	if err != nil {
		logger.Panicf("证书列表查询失败: %s", err)
	}
	certificates := make(map[string]*ssl.Certificates)
	for _, certificate := range rs.Response.Certificates {
		if *certificate.Status != 0 && *certificate.Status != 1 && *certificate.Status != 4 {
			continue
		}
		// 兼容一个证书对应多个地址的情况
		if certificate.CertSANs != nil {
			for _, s := range certificate.CertSANs {
				certificates[*s] = certificate
			}
		} else {
			certificates[*certificate.Domain] = certificate
		}
	}
	logger.Printf("查询到有效证书记录%d条，涉及域名%d个。注意：本程序一次最大拉取距离过期时间最近的50条记录",
		len(rs.Response.Certificates), len(certificates))
	diffDaysLimit := viper.GetInt64("diff-days-limit")
	for _, server := range servers {
		logger.SetPrefix("[" + server.Domain() + "] ")
		// 0.过滤非名下域名
		if !isBelong(server.Domain()) {
			logger.Println("暂时只支持为同账号名下域名自动申请证书 >>> 跳过")
			continue
		}
		// 1.检查本地证书
		if !server.CertExpired() {
			logger.Println("本地证书未超过过期时间 >>> 跳过")
			continue
		}
		certificate, ok := certificates[server.Domain()]
		if !ok {
			logger.Println("无证书记录 >>> 申请并下载")
			err = server.UpdateCert()
		} else {
			if *certificate.Status == 0 {
				logger.Println("服务器证书审核中 >>> 尝试下载")
				err = server.Query4DownLoadCert(*certificate.CertificateId)
			} else {
				diffDays := -carbon.Parse(*certificate.CertEndTime).DiffInDays()
				if diffDays > diffDaysLimit {
					logger.Printf("服务器证书过期时间 %s，%d天后过期，超过%d天 >>> 下载", *certificate.CertEndTime, diffDays, diffDaysLimit)
					err = server.DownloadCert(*certificate.CertificateId)
				} else {
					logger.Printf("服务器证书过期时间 %s，%d天后过期， >>> 申请并下载", *certificate.CertEndTime, diffDays)
					err = server.UpdateCert()
				}
			}
		}
		if err != nil {
			logger.Println(err)
			continue
		}
		err = ExecShel(viper.GetString("nginx.cmd.test"))
		if err != nil {
			logger.Println(err)
			continue
		}
		logger.Println("证书配置通过验证")
		err = ExecShel(viper.GetString("nginx.cmd.reload"))
		if err != nil {
			logger.Println(err)
			continue
		}
		logger.Println("证书更新完成")
	}
}
